package org.ghost.springboot2.demo.util;


import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.yaml.snakeyaml.util.UriEncoder;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

public class UriUtil {
    private static final Logger logger = LoggerFactory.getLogger(UriUtil.class);

    /**
     * 对对象进行urlencode编号
     *
     * @param data 对象
     * @return String
     */
    public static String encode(Object data) {
        return encode(data, false);
    }

    public static String encode(String data) {
        return UriEncoder.encode(data);
    }

    /**
     * 对对象进行urlencode编号
     *
     * @param data         对象
     * @param keyUpperCase 是否将key首字符大写
     * @return String
     */
    public static String urlEncode(Object data, Boolean keyUpperCase) {
        if (data == null) {
            return null;
        }

        StringBuilder stringBuilder = getStringBuilder(data, keyUpperCase);
        if (stringBuilder == null) {
            return null;
        }
        String encodedUrl;
        try {
            encodedUrl = URLEncoder.encode(stringBuilder.substring(1), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            if (logger.isWarnEnabled()) {
                logger.warn("urlencode 编码失败, 错误信息: {}, {}", e.getMessage(), e);
            }
            return null;
        }
        return encodedUrl;
    }

    /**
     * 对对象进行urlencode编号
     *
     * @param data         对象
     * @param keyUpperCase 是否将key首字符大写
     * @return String
     */
    public static String encode(Object data, Boolean keyUpperCase) {
        if (data == null) {
            return null;
        }

        StringBuilder stringBuilder = getStringBuilder(data, keyUpperCase);
        if (stringBuilder == null) {
            return null;
        }
        return UriEncoder.encode(stringBuilder.substring(1));
    }

    private static StringBuilder getStringBuilder(Object data, Boolean keyUpperCase) {
        StringBuilder stringBuilder = new StringBuilder();
        PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(data.getClass());
        try {
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                String name = propertyDescriptor.getName();
                name = keyUpperCase ? StringUtils.capitalize(name) : name;
                Method method = propertyDescriptor.getReadMethod();
                Object object = method.invoke(data);
                if (object instanceof List) {
                    List mess = (List) object;
                    for (Object lo : mess) {
                        String value = lo != null ? lo.toString() : "";
                        stringBuilder.append('&').append(name).append('=').append(value);
                    }
                } else {
                    String value = object != null ? object.toString() : "";
                    stringBuilder.append('&').append(name).append('=').append(value);
                }
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            if (logger.isWarnEnabled()) {
                logger.warn("urlencode 编码失败, 错误信息: {}, {}", e.getMessage(), e);
            }
            return null;
        }
        return stringBuilder;
    }

    public static String urlParaEncode(Object data) {
        return urlParaEncode(data, false);
    }

    /**
     * 对对象进行urlEncode编号
     *
     * @param data         对象
     * @param keyUpperCase 是否将key首字符大写
     * @return String
     */
    public static String urlParaEncode(Object data, Boolean keyUpperCase) {
        Map<String, String> rtnMap = getResultMap(data, keyUpperCase);
        if (MapUtils.isNotEmpty(rtnMap)) {
            StringBuilder builder = new StringBuilder();
            for (Map.Entry<String, String> item : rtnMap.entrySet()) {
                if (StringUtils.isNotBlank(item.getKey()) && StringUtils.isNotBlank(item.getValue())) {
                    String value = "";
                    try {
                        value = URLEncoder.encode(item.getValue(), "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        logger.warn("*****UriUtil.urlEncode编码失败, 错误信息: {}, {}", e.getMessage(), e);
                    }
                    if (builder.length() == 0) {
                        builder.append(item.getKey()).append('=').append(value);
                    } else {
                        builder.append('&').append(item.getKey()).append('=').append(value);
                    }
                }
            }

            return builder.toString();
        }

        return "";
    }

    private static Map<String, String> getResultMap(Object data, boolean keyUpperCase) {
        Map<String, String> rtnMap = new HashMap<String, String>();
        if (data != null) {
            Field[] fields = data.getClass().getDeclaredFields();
            for (Field field : fields) {
                String name = field.getName();
                if (keyUpperCase) {
                    name = StringUtils.capitalize(name);
                }

                Object object = null;
                try {
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(), data.getClass());
                    Method method = pd.getReadMethod();
                    if (method != null) {
                        object = method.invoke(data);
                    }
                } catch (IntrospectionException e) {
                    logger.warn("*****UriUtil.getResultMap中PropertyDescriptor获取失败, 错误信息: {}, {}", e.getMessage(), e);
                } catch (IllegalAccessException e) {
                    logger.warn("*****UriUtil.getResultMap中反射get方法权限问题, 错误信息: {}, {}", e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    logger.warn("*****UriUtil.getResultMap中反射getReadMethod失败, 错误信息: {}, {}", e.getMessage(), e);
                }

                if (Objects.isNull(object)) {
                    //
                } else if (object instanceof List) {
                    List<Object> list = (List<Object>) object;
                    String value = list.stream().filter(Objects::nonNull).map(Object::toString).reduce("", (a, b) -> StringUtils.isBlank(a) ? b : a + "," + b);
                    rtnMap.put(name, value);
                } else if (object.getClass().isArray()) {
                    Object[] array = (Object[]) object;
                    String value = Stream.of(array).filter(Objects::nonNull).map(Object::toString).reduce("", (a, b) -> StringUtils.isBlank(a) ? b : a + "," + b);
                    rtnMap.put(name, value);
                } else {
                    rtnMap.put(name, object.toString());
                }
            }
        }

        return rtnMap;
    }
}
